package com.n9.buymsg.service.qqonline;

import com.n9.buymsg.AppContext;
import com.n9.buymsg.event.*;
import com.n9.buymsg.view.vo.QqVo;
import com.n9.qq.android.mock.LoginResult;
import com.n9.qq.android.mock.MockAq;
import com.n9.qq.android.mock.MsgListener;
import com.n9.qq.android.mock.VfCodeHandler;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * QQ消息服务
 * @Author: ice
 * @Date: 2020-07-06 8:51
 */
public class QQService implements EventPublisher {
    private MsgListener msgListener = new DefaultMsgListener();

    private static final Map<Long, MockAq> MOCK_AQS = new ConcurrentHashMap<>();
    private VfCodeHandler vfCodeHandler;//验证码处理器

    private static final int LOGIN_FAILED_RETRY_TIMES = 3;//登陆失败重试次数

    public QQService(VfCodeHandler vfCodeHandler) {
        this.vfCodeHandler = vfCodeHandler;
    }

    public boolean login(QqVo vo) {
        if (Objects.isNull(vo) || Objects.isNull(vo.getUin()) || StringUtils.isEmpty(vo.getPassword())) {
            return false;
        }

        long qqUin = vo.getUin();
        if (isOnline(qqUin)) {
            showLogMsg(String.format("%d已登陆", qqUin));
            return true;
        }


        showLogMsg(qqUin + "开始登陆");
        MockAq mockAq = new MockAq(vo.getUin(), vo.getPassword(), msgListener, null);
        mockAq.setOfflineListener(client ->{
            showLogMsg(String.format("%d已掉线，开始重新登陆", mockAq.getQqUin()));
            for (int i = 1; i <= LOGIN_FAILED_RETRY_TIMES; i++) {
                LoginResult loginResult = mockAq.reLogin(vfCodeHandler);
                if (Objects.equals(LoginResult.SUCCESS, loginResult)) {
                    showLogMsg(String.format("%d掉线重登成功", qqUin));
                    return;
                } else {
                    showLogMsg(String.format("%d第%d次掉线重登失败:%s", qqUin, i, loginResult.toString()));
                }
            }
        });

        for (int i = 1; i <= LOGIN_FAILED_RETRY_TIMES ; i++) {
            LoginResult result = mockAq.login(vfCodeHandler);
            if (Objects.equals(LoginResult.SUCCESS, result)) {
                MOCK_AQS.put(qqUin, mockAq);
                showLogMsg(String.format("%d登陆成功", qqUin));

                vo.setNick(mockAq.getNick());
                vo.setLoginTime(DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"));
                vo.setStatus("登陆成功");
                vo.setGroupCount(Long.toString(mockAq.getGroupCount()));

                publishEvent(new QQLoginSuccessEvent(vo));
                return true;
            } else {
                showLogMsg(String.format("%d第%d次登陆失败:%s", qqUin, i, result));
            }
        }
        return false;
    }

    /**
     * 判断该账号是否在线
     * @param qqUin
     * @return
     */
    private boolean isOnline(long qqUin) {
        MockAq mockAq = MOCK_AQS.get(qqUin);
        return Objects.nonNull(mockAq) && mockAq.isOnline();
    }


    /**
     * 显示日志信息
     * @param logMsg
     */
    private void showLogMsg(String logMsg) {
        publishEvent(new LogMsgViewEvent(logMsg));
    }

    @Override
    public void publishEvent(AppEvent appEvent) {
        AppContext.getInstance().publishEvent(appEvent);
    }

    @Override
    public void publishEvent(AppEvent appEvent, Callback callback) {
        AppContext.getInstance().publishEvent(appEvent, callback);
    }
}
